#include "Textbox.h"

#define TEXTBOX_DEFAULT_WIDTH 200
#define TEXTBOX_DEFAULT_HEGHT 40

Textbox::Textbox(std::string defText,int posX, int posY, Widget *parent)
	: WidgetClickeableWithText(defText,Color::BLANCO,
			TEXTBOX_DEFAULT_WIDTH,TEXTBOX_DEFAULT_HEGHT,posX, posY, parent) {

	// Flags
	enable = true;
	selected = false;
	inputChanged = false;
	cursorMoved = false;
	mouseLeftBtnPressed = false;
	mouseIsOver = false;
	keyDown = false;
	isChar = false;
	backSpaceKey = false;
	deleteKey = false;
	leftKey = false;
	rightKey = false;
	keyPressed = false;

	keyState = 0;
	screenPosCursor = 0;
	stringPosCursor = 0;
	yMargin = 0;

	font = NULL;
	renderedText = NULL;

	//Recalculate font size to fit in the text area
	resizeFontToTextArea();
}

Textbox::Textbox(std::string defText,int posX, int posY, int width, int height, Widget *parent)
	: WidgetClickeableWithText(defText,Color::BLANCO,
			width,height,posX, posY, parent) {

	// Flags
	enable = true;
	selected = false;
	inputChanged = false;
	cursorMoved = false;
	mouseLeftBtnPressed = false;
	mouseIsOver = false;
	keyDown = false;
	isChar = false;
	backSpaceKey = false;
	deleteKey = false;
	leftKey = false;
	rightKey = false;
	keyPressed = false;

	keyState = 0;
	screenPosCursor = 0;
	stringPosCursor = 0;
	yMargin = 0;

	font = NULL;
	renderedText = NULL;

	//Recalculate font size to fit in the text area
	resizeFontToTextArea();
}

void Textbox::handleEvent(Event event) {
	mouseLeftBtnPressed = ((event.getButtonState() == Pressed) && (event.getMouseButton() == MouseButtonLeft));
	mouseIsOver = isMouseOver(event);
	keyDown = (event.getType() == KeyPressed);

	this->keyState = event.getType();

	//Mouse button pressed over the textbox area
	if(mouseLeftBtnPressed && mouseIsOver)
	{
		selected = true;
	}
	else if (mouseLeftBtnPressed && !mouseIsOver){
		selected = false;
	}

	if(selected && !keyPressed && keyDown){
		isChar = ((event.getKeyUnicode() >= (Uint16) 32)
				&& (event.getKeyUnicode() <= (Uint16) 255));
		backSpaceKey = (event.getKey() == Backspace);
		keyPressed = true;
		tempInput = (char) event.getKeyUnicode();
	}

	WidgetClickeableWithText::handleEvent(event);
}

void Textbox::resolve()
{
	if (selected && keyState == KeyReleased && keyPressed ) {
		keyPressed = false;
		inputChanged = true;
	}

	if(selected && enable && inputChanged)
	{
		if(isChar)
		{
			char letra = tempInput;
			//Append the character
			text.insert(stringPosCursor++,
					std::string(1, letra));
			// Flag Cursor Moved
			cursorMoved = true;
			// Flag Text Changed
			inputChanged = true;
		}
		else if (!text.empty()) {
			if( backSpaceKey && stringPosCursor > 0)
			{
				//Remove the corresponding character
				text.erase(--stringPosCursor, 1);
				// Flag Cursor Moved
				cursorMoved = true;
				// Flag Text Changed
				inputChanged = true;
			}
		}
	}

	WidgetClickeableWithText::resolve();
}

void Textbox::drawBox(SDL_Surface* s)
{
	SDL_Rect widgetArea = widArea;
	SDL_FillRect( s, &widgetArea, (selected) ? Color::CELESTE : Color::BLANCO);
}

int Textbox::getTextWidth(const std::string& txt)
{
	if (txt.empty())
		return 0;
	int w, h;
	TTF_SizeText(font, txt.c_str(), &w, &h);
	return w;
}

void Textbox::renderText() {
	if (renderedText != NULL)
		SDL_FreeSurface (renderedText);

	//Rendering input
	SDL_Color textColor;
	textColor.b = 255;
	textColor.g = 0;
	textColor.r = 0;
	renderedText = TTF_RenderText_Blended(font, text.c_str(), textColor);
	//Keeping hight
	textSrcArea.h = this->renderedText->clip_rect.h;
	textSrcArea.y = this->renderedText->clip_rect.y;
	//Width limit to text area
	textSrcArea.w = textDstArea.w;
	inputChanged = false;
}

void Textbox::reCalculateCursorPosition() {
	std::string partialMsg(text, 0, stringPosCursor);
	Sint16 difTotVsPart = getTextWidth(partialMsg) - textSrcArea.x;
	if (difTotVsPart < 0) {
		textSrcArea.x += difTotVsPart;
		screenPosCursor = 0;
	} else if (difTotVsPart > textDstArea.w) {
		textSrcArea.x += difTotVsPart - textDstArea.w;
		screenPosCursor = textDstArea.w;
	} else {
		screenPosCursor = difTotVsPart;
	}

	screenPosCursor += this->textDstArea.x;
	cursorMoved = false;
}

void Textbox::drawText(SDL_Surface* s)
{
	textDstArea = widArea;
	textDstArea.y += yMargin;
	textDstArea.x += MARGIN;
	textDstArea.w = widArea.w - 2 * MARGIN;

	if(!text.empty())
	{
		//If the input was changed it must be rendered again
		if (inputChanged)
		{
			renderText();
		}

		//If the cursor was moved it must recalculate the position to render
		if(selected && cursorMoved && enable)
		{
			reCalculateCursorPosition();
		}

		SDL_BlitSurface(renderedText, &textSrcArea, s, &textDstArea);
	}
	else if(selected && enable)
	{
		this->screenPosCursor = textDstArea.x;
	}
}

void Textbox::drawCursor(SDL_Surface* s)
{
	if(!cursorTimer.is_started())
		cursorTimer.start();

	float secs = cursorTimer.get_ticks() / 1000.0;

	if (secs >= 1.0 / CURSOR_BLINK_RATE)
	{
		vlineColor(s, screenPosCursor, widArea.y + 1, widArea.y + widArea.h - 3, Color::AZUL);
		cursorTimer.start();
	}

}

void Textbox::resizeFontToTextArea() {
	//Calculating the appropriate font size
	int fontSize = DEFAULT_FONT_SIZE;
	font = TTF_OpenFont(DEFAULT_FONT, fontSize);
	Uint16 fontHe = TTF_FontHeight(font);
	if (fontHe > parcel->height - 2 * MARGIN) {
		while (fontHe > parcel->height - 2 * MARGIN && fontSize > 1) {
			--fontSize;
			TTF_CloseFont(this->font);
			font = TTF_OpenFont(DEFAULT_FONT, fontSize);

			fontHe = TTF_FontHeight(font);
		}
	} else if (fontHe < parcel->height - 2 * MARGIN) {
		while (fontHe < parcel->height - 2 * MARGIN) {
			++fontSize;
			TTF_CloseFont(this->font);
			font = TTF_OpenFont(DEFAULT_FONT, fontSize);

			fontHe = TTF_FontHeight(font);
		}
		TTF_CloseFont (font);
		font = TTF_OpenFont(DEFAULT_FONT, --fontSize);
	}
}

void Textbox::showOn(SDL_Surface* surface){


	inputChanged = (text.empty()) ? false : true;
	cursorMoved = inputChanged;

	screenPosCursor = parcel->posX + MARGIN;
	stringPosCursor = text.length();

	textSrcArea.x = 0;

	widArea = *(parcel->getRectangle());

	//Vertical align
	yMargin = (parcel->height - TTF_FontHeight(font)) / 2;

	drawBox(surface);
	drawText(surface);
	if(enable && selected)
		drawCursor(surface);
}

std::string Textbox::getInput() {
	return this->text;
}

Textbox::~Textbox(){
	//TTF_CloseFont (font);
	SDL_FreeSurface(renderedText);
}
